package net.ufrog.common.utils;

import net.ufrog.common.Link;
import net.ufrog.common.Logger;
import net.ufrog.common.exception.ServiceException;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 对象工具
 * 
 * @author ultrafrog
 * @version 1.0, 2014-02-10
 * @since 1.0
 */
public class Objects {

    /** 构造函数 */
    private Objects() {}

    /**
     * 强制转换
     *
     * @param obj 被转换对象
     * @param clazz 转换类型
     * @return 结果类型对象
     */
    public static <T> T cast(Object obj, Class<T> clazz) {
        return clazz.cast(obj);
    }

    /**
     * 判断对象是否相同
     *
     * @param one 待比较对象
     * @param another 比较对象
     * @return 比较结果
     */
    public static boolean equals(Object one, Object another) {
        return (one == another || (one != null && one.equals(another)));
    }

    /**
     * 生成列表
     *
     * @param ts 数组
     * @return 列表
     */
    @SafeVarargs
    public static <T> List<T> list(T... ts) {
        return Stream.of(ts).collect(Collectors.toList());
    }

    /**
     * 生成映射表
     *
     * @param key 键值
     * @param value 内容
     * @return 映射对象
     */
    public static <K, V> Map<K, V> map(K key, V value) {
        Map<K, V> map = new HashMap<>();
        map.put(key, value);
        return map;
    }

    /**
     * 数组转换为映射<br>
     * 遵循两个元素（键/值）为一组
     *
     * @param objs 参数数组
     * @return 映射对象
     */
    public static Map<String, Object> map(Object... objs) {
        return map(Object.class, objs);
    }

    /**
     * 数组转换为映射<br>
     * 遵循两个元素（键/值）为一组
     *
     * @param valueType 内容类型
     * @param objs 参数数组
     * @param <T> 内容泛型
     * @return 映射对象
     */
    public static <T> Map<String, T> map(Class<T> valueType, Object... objs) {
        if (objs == null || objs.length == 0) return Collections.emptyMap();
        if (objs.length % 2 != 0) throw new ServiceException("objs length is " + objs.length + ".");

        Map<String, T> map = new HashMap<>();
        IntStream.range(0, objs.length).filter(idx -> idx % 2 == 0).forEach(idx -> map.put(String.valueOf(objs[idx]), valueType.cast(objs[++idx])));
        return map;
    }

    /**
     * 读取所有字段
     *
     * @param clazz 类型
     * @return 字段列表<br>包括父类字段
     */
    public static List<Field> getFields(Class<?> clazz) {
        List<Field> lField = new ArrayList<>();
        Class<?> superClass = clazz.getSuperclass();
        if (superClass != null) {
            lField.addAll(getFields(superClass));
        }
        lField.addAll(Objects.list(clazz.getDeclaredFields()));
        return lField;
    }

    /**
     * 复制属性
     *
     * @param dest 目标对象
     * @param source 原对象
     * @param copynull 是否复制空数据
     * @param exculdes 排除的属性
     * @param <T> 对象泛型
     * @return 目标对象
     */
    public static <T> T copyProperties(T dest, T source, Boolean copynull, String... exculdes) {
        List<Field> lField = getFields(source.getClass());
        lField.forEach(field -> {
            if (Strings.in(field.getName(), exculdes) || Modifier.isFinal(field.getModifiers())) {
                Logger.debug("exclude field '%s'", field.getName());
            } else {
                field.setAccessible(true);
                try {
                    Object value = field.get(source);
                    if (value != null || copynull) {
                        field.set(dest, value);
                        Logger.debug("copy property '%s' to dest", field.getName());
                    } else {
                        Logger.debug("property '%s' value is null!", field.getName());
                    }
                } catch (IllegalAccessException e) {
                    throw new ServiceException(e.getMessage(), e);
                }
            }
        });
        return dest;
    }

    /**
     * 复制属性
     *
     * @param dest 目标对象
     * @param source 原对象
     * @param exculdes 排除的属性
     * @param <T> 对象泛型
     * @return 目标对象
     */
    public static <T> T copyProperties(T dest, T source, String... exculdes) {
        return copyProperties(dest, source, Boolean.FALSE, exculdes);
    }

    /**
     * 序列化对象
     *
     * @param object 对象
     * @return 对象字节数组
     */
    public static byte[] serialize(Object object) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(object);
            Logger.debug("serialize class: %s", object.getClass().getName());
            return baos.toByteArray();
        } catch (IOException e) {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * 反序列化对象
     *
     * @param bytes 字节数组
     * @return 对象
     */
    public static Object deserialize(byte[] bytes) {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais)) {
            Object object = ois.readObject();
            Logger.debug("deserialize class: %s", object.getClass().getName());
            return object;
        } catch (IOException | ClassNotFoundException e) {
            throw new ServiceException(e.getMessage(), e);
        }
    }

    /**
     * 关闭连接
     *
     * @param closeable 待关闭对象
     */
    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                Logger.error(e.getMessage());
            }
        }
    }
}
